import { useCallback, useEffect, useState } from "react";
import { ActivityIndicator, Pressable, ScrollView, StyleSheet, Text, View } from "react-native";
import { SafeAreaView } from "react-native-safe-area-context";
import { Stack } from "expo-router";

import { PageHeader } from "@/components/page-header";
import { apiRequestWithMeta } from "@/utils/api";
import { CircleThumbnail } from "@/components/circle-thumbnail";
import { resolveAssetUrl } from "@/constants/config";

const palette = {
  background: "#fdf7fb",
  surface: "#ffffff",
  accent: "#ff8fb1",
  border: "rgba(214, 106, 138, 0.18)",
  textPrimary: "#2f1f2b",
  textMuted: "#78657a",
  textHint: "#9c8aa0",
  textAccent: "#d66a8a",
};

type LeaderboardItem = {
  user_id: number;
  username?: string;
  display_name?: string;
  total_spent: number;
  orders_count: number;
  cover_image?: string | null;
  avatar?: string | null;
};

type LeaderboardMeta = {
  hint?: string | null;
  count?: number;
  page?: number;
  limit?: number;
  has_more?: boolean;
};

const TITLE_TEXT = "消费总榜";
const DEFAULT_HINT = "榜单基于真实订单累计消费金额（仅统计已完成支付订单），实时更新。";
const FALLBACK_ERROR = "排行榜加载失败，请稍后重试。";
const LOADING_TEXT = "正在获取榜单，请稍候...";
const HINT_TITLE = "轻提示";
const EMPTY_TEXT = "当前没有任何消费数据。";
const LOAD_MORE_TEXT = "加载更多";
const PAGE_SIZE = 20;

const formatCurrency = (value: number) => {
  if (!Number.isFinite(value)) {
    return "¥0.00";
  }
  return `¥${value.toFixed(2)}`;
};

export default function LeaderboardScreen() {
  const [items, setItems] = useState<LeaderboardItem[]>([]);
  const [hint, setHint] = useState<string>(DEFAULT_HINT);
  const [page, setPage] = useState(1);
  const [hasMore, setHasMore] = useState(false);
  const [isLoading, setLoading] = useState(true);
  const [isLoadingMore, setLoadingMore] = useState(false);
  const [error, setError] = useState<string | null>(null);

  const fetchLeaderboard = useCallback(
    async (pageToLoad: number, append: boolean) => {
      if (append) {
        setLoadingMore(true);
      } else {
        setLoading(true);
        setError(null);
      }

      try {
        const { data, meta } = await apiRequestWithMeta<LeaderboardItem[], LeaderboardMeta>(
          "/leaderboard/users",
          { query: { page: pageToLoad, limit: PAGE_SIZE } },
        );
        const list = Array.isArray(data) ? data : [];

        setItems((prev) => {
          if (!append) {
            return list;
          }
          const existing = new Set(prev.map((item) => item.user_id));
          const merged = list.filter((item) => !existing.has(item.user_id));
          return [...prev, ...merged];
        });

        const nextHint = meta?.hint?.trim();
        setHint(nextHint && nextHint.length > 0 ? nextHint : DEFAULT_HINT);
        setHasMore(Boolean(meta?.has_more));
        setPage(pageToLoad);
      } catch (err) {
        if (!append) {
          const message = err instanceof Error ? err.message : FALLBACK_ERROR;
          setError(message);
          setItems([]);
        }
      } finally {
        if (append) {
          setLoadingMore(false);
        } else {
          setLoading(false);
        }
      }
    },
    [],
  );

  useEffect(() => {
    fetchLeaderboard(1, false);
  }, [fetchLeaderboard]);

  const handleLoadMore = useCallback(() => {
    if (isLoadingMore || !hasMore) {
      return;
    }
    fetchLeaderboard(page + 1, true);
  }, [fetchLeaderboard, hasMore, isLoadingMore, page]);

  const hintText = hint?.trim().length ? hint.trim() : DEFAULT_HINT;
  const hasData = items.length > 0;

  return (
    <SafeAreaView style={styles.safeArea}>
      <Stack.Screen options={{ title: TITLE_TEXT }} />
      <PageHeader title={TITLE_TEXT} />
      <ScrollView contentContainerStyle={styles.container}>
        {hintText ? (
          <View style={styles.hintBox}>
            <Text style={styles.hintTitle}>{HINT_TITLE}</Text>
            <Text style={styles.hintText}>{hintText}</Text>
          </View>
        ) : null}

        <View style={styles.card}>
          {isLoading ? (
            <View style={styles.stateBox}>
              <ActivityIndicator color={palette.accent} />
              <Text style={styles.stateText}>{LOADING_TEXT}</Text>
            </View>
          ) : error ? (
            <View style={styles.stateBox}>
              <Text style={styles.stateText}>{error}</Text>
            </View>
          ) : hasData ? (
            <>
              {items.map((item, index) => {
                const rank = index + 1;
                const displayName =
                  (item.display_name && item.display_name.trim()) ||
                  (item.username && item.username.trim()) ||
                  `用户 ${item.user_id}`;
                const amount = formatCurrency(item.total_spent);
                const thumbSource =
                  item.cover_image || item.avatar ? resolveAssetUrl(item.cover_image || item.avatar || "") : null;
                return (
                  <View
                    key={`${item.user_id}-${rank}`}
                    style={[styles.row, index === items.length - 1 && !hasMore && styles.rowLast]}
                  >
                    <View style={styles.rankBadge}>
                      <Text style={styles.rankText}>{rank}</Text>
                    </View>
                    <CircleThumbnail uri={thumbSource} size={48} />
                    <View style={styles.userBlock}>
                      <Text style={styles.userName}>{displayName}</Text>
                      <Text style={styles.meta}>
                        累计消费 <Text style={styles.amount}>{amount}</Text>
                        {" · "}订单 {item.orders_count} 笔
                      </Text>
                    </View>
                  </View>
                );
              })}
              {hasMore ? (
                <Pressable
                  style={[styles.loadMoreButton, isLoadingMore && styles.loadMoreDisabled]}
                  onPress={handleLoadMore}
                  disabled={isLoadingMore}
                >
                  {isLoadingMore ? (
                    <ActivityIndicator color={palette.accent} size="small" />
                  ) : (
                    <Text style={styles.loadMoreText}>{LOAD_MORE_TEXT}</Text>
                  )}
                </Pressable>
              ) : null}
            </>
          ) : (
            <View style={styles.stateBox}>
              <Text style={styles.stateText}>{EMPTY_TEXT}</Text>
            </View>
          )}
        </View>
      </ScrollView>
    </SafeAreaView>
  );
}

const styles = StyleSheet.create({
  safeArea: { flex: 1, backgroundColor: palette.background },
  container: { padding: 16, gap: 16 },
  card: {
    borderRadius: 24,
    backgroundColor: palette.surface,
    paddingVertical: 8,
    borderWidth: 1,
    borderColor: palette.border,
  },
  hintBox: {
    padding: 16,
    borderRadius: 18,
    borderWidth: 1,
    borderColor: palette.border,
    backgroundColor: "rgba(255,143,177,0.08)",
    gap: 6,
  },
  hintTitle: {
    fontSize: 13,
    fontWeight: "700",
    color: palette.textAccent,
    letterSpacing: 2,
  },
  hintText: {
    fontSize: 13,
    color: palette.textMuted,
    lineHeight: 20,
  },
  row: {
    flexDirection: "row",
    alignItems: "center",
    gap: 12,
    paddingVertical: 14,
    paddingHorizontal: 16,
    borderBottomWidth: StyleSheet.hairlineWidth,
    borderBottomColor: "#eee",
  },
  rowLast: {
    borderBottomWidth: 0,
  },
  rankBadge: {
    width: 26,
    height: 26,
    borderRadius: 13,
    alignItems: "center",
    justifyContent: "center",
    backgroundColor: "rgba(255, 143, 177, 0.15)",
  },
  rankText: { fontSize: 13, fontWeight: "700", color: palette.textPrimary },
  userBlock: { flex: 1, gap: 4 },
  userName: { fontSize: 15, fontWeight: "600", color: palette.textPrimary },
  meta: { fontSize: 12, color: palette.textHint },
  amount: { color: palette.textAccent, fontWeight: "700" },
  stateBox: {
    paddingVertical: 24,
    alignItems: "center",
    justifyContent: "center",
    gap: 12,
  },
  stateText: { fontSize: 13, color: palette.textMuted },
  loadMoreButton: {
    marginTop: 4,
    paddingVertical: 12,
    alignItems: "center",
  },
  loadMoreDisabled: {
    opacity: 0.6,
  },
  loadMoreText: {
    fontSize: 13,
    color: palette.textAccent,
    fontWeight: "600",
  },
});
